package binderipc

import android.os.IBinder
import android.os.Parcel
import android.os.ParcelFileDescriptor
import android.util.Log
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileDescriptor
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy

class PassValueProxy(remote: IBinder, parent: File) : IPassValue, InvocationHandler {

    private val mRemote = remote
    private val mParent = parent

    override fun asBinder(): IBinder {
        return mRemote
    }

    override fun passInt(value: Int): Int {
        val data = Parcel.obtain()
        val reply = Parcel.obtain()
        try {
            data.writeInterfaceToken(IPassValue.descriptor)
            data.writeInt(value)
            data.writeNoException()
            Log.d("PassValueService", "---transact---")
            mRemote.transact(IPassValue.PASS_INT_TRANSACTION, data, reply, 0)
            //读异常 读数据
            reply.readException()
            //return reply.readInt()
            return reply.readValue(javaClass.classLoader) as? Int ?: 0
        } finally {
            reply.recycle()
            data.recycle()
        }
    }

    override fun passString(str: String) {
        val data = Parcel.obtain()
        val reply = Parcel.obtain()
        try {
            data.writeInterfaceToken(IPassValue.descriptor)
            data.writeString(str)
            data.writeNoException()
            mRemote.transact(IPassValue.PASS_STRING_TRANSACTION, data, reply, 0)
            //读异常 读数据
            reply.readException()
            val value = reply.readString()
        } finally {
            reply.recycle()
            data.recycle()
        }
    }

    override fun updateValue(strValue: String) {
        val data = Parcel.obtain()
        val reply = Parcel.obtain()
        try {
            data.writeInterfaceToken(IPassValue.descriptor)
            data.writeString(strValue)
            data.writeNoException()
            mRemote.transact(IPassValue.PASS_VALUE_TRANSACTION, data, reply, 0)
            //读异常 读数据
            reply.readException()
            val value = reply.readString()
        } finally {
            reply.recycle()
            data.recycle()
        }
    }

    override fun transactFileDescriptor(pfd: ParcelFileDescriptor?) {
        val data = Parcel.obtain()
        val reply = Parcel.obtain()
        try {
            //val pfds = ParcelFileDescriptor.createReliablePipe()
            //val pfdRead = pfds[0]
            //val pfdWrite = pfds[1]

            val file = File(mParent, "file0911.txt")
            file.delete()
            file.createNewFile()

            data.writeInterfaceToken(IPassValue.descriptor)
            //data.writeValue(pfdWrite)
            data.writeNoException()
            mRemote.transact(IPassValue.TRANSACT_FILE_DESCRIPTOR_TRANSACTION, data, reply, 0)

            Log.d("PassValueProxy","-----------hahaha----------------")

            reply.readException()
            val pfdRead = reply.readValue(javaClass.classLoader) as? ParcelFileDescriptor

            if (pfdRead == null) {
                Log.d("PassValueProxy","pfdRead == null")
            }

            val inputStream = ParcelFileDescriptor.AutoCloseInputStream(pfdRead)

            val outputStream = FileOutputStream(file)
            val buffer = ByteArray(1024)
            var length = inputStream.read(buffer)
            while (length != -1) {
                outputStream.write(buffer, 0, length)
                length = inputStream.read(buffer)
            }
            outputStream.close()
            pfdRead?.close()
        } catch (ex: IOException) {
            ex.printStackTrace()
        } finally {
            reply.recycle()
            data.recycle()
        }
    }

    override fun getPFD(): ParcelFileDescriptor? {
        val data = Parcel.obtain()
        val reply = Parcel.obtain()
        try {
            val file = File(mParent, "0011.jpg")
            file.delete()
            file.createNewFile()

            data.writeInterfaceToken(IPassValue.descriptor)
            data.writeNoException()
            mRemote.transact(IPassValue.GET_PFD_TRANSACTION, data, reply, 0)

            reply.readException()
            val parcelFileDescriptor = reply.readValue(javaClass.classLoader) as? ParcelFileDescriptor
            parcelFileDescriptor?.let {
                val fileDescriptor = it.fileDescriptor
                val fis =
                    BufferedInputStream(FileInputStream(fileDescriptor))
                val fos = BufferedOutputStream(FileOutputStream(file))
                val bytes = ByteArray(1024)
                var length = fis.read(bytes)
                while (length != -1) {
                    fos.write(bytes, 0, length)
                    length = fis.read(bytes)
                }
                fis.close()
                fos.close()
            }
            return parcelFileDescriptor
        } finally {
            reply.recycle()
            data.recycle()
        }
    }

    override fun passValueByOneWay(value0: Int, value1: Int) : Int {
        val data = Parcel.obtain()
        val reply = Parcel.obtain()
        try {
            data.writeInterfaceToken(IPassValue.descriptor)
            data.writeInt(value0)
            data.writeInt(value1)
            data.writeNoException()
            mRemote.transact(
                IPassValue.PASS_VALUE_BY_ONEWAY_TRANSACTION,
                data,
                reply,
                //0
                IBinder.FLAG_ONEWAY
            )
            reply.readException()
            return reply.readInt() + 100
        } finally {
            reply.recycle()
            data.recycle()
        }
    }

    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
        return if ("passInt" == method?.name) {
            Log.d(
                "PassValueProxy",
                "override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?)"
            )
            method.invoke(mRemote, *args.orEmpty())
        } else {
            null
        }
    }

    fun getProxyInstance() : Any? {
        return Proxy.newProxyInstance(
            mRemote.javaClass.classLoader,
            mRemote.javaClass.interfaces,
            this
        )
    }
}